/*
 * Proto Streamer
 * Copyright (C) 2009 John Pritchard.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 */
package p.c;

import java.io.IOException;
import java.io.PrintStream;

/**
 * @author jdp
 */
public final class Headers
    extends Object
{
    private final static String Sep = ": ";
    private final static boolean StartsWithIgnoreCase(String a, String b){
        int alen = a.length();
        int blen = b.length();
        if (blen < alen){
            String c = a.substring(0,blen);
            return (c.equalsIgnoreCase(b));
        }
        else if (blen == alen)
            return (a.equalsIgnoreCase(b));
        else
            return false;
    }
    private final static String[] Add(String[] a, String b){
        if (null == a){
            return new String[]{b};
        }
        else {
            int alen = a.length;
            String[] c = new String[alen+1];
            System.arraycopy(a,0,c,0,alen);
            c[alen] = b;
            return c;
        }
    }


    protected String[] list;


    public Headers(){
        super();
    }


    public void clear(){
        this.list = null;
    }
    public int indexOf(String name){
        String[] headers = this.list;
        if (null != headers){
            String search = name+Sep;
            for (int cc = 0, count = headers.length; cc < count; cc++){
                String line = headers[cc];
                if (StartsWithIgnoreCase(line,search))
                    return cc;
            }
        }
        return -1;
    }
    public boolean contains(String name){
        return (-1 < this.indexOf(name));
    }
    public boolean containsNot(String name){
        return (0 > this.indexOf(name));
    }
    public String valueOf(String name){
        String[] headers = this.list;
        if (null != headers){
            String search = name+Sep;
            for (int cc = 0, count = headers.length; cc < count; cc++){
                String line = headers[cc];
                if (StartsWithIgnoreCase(line,search))
                    return line.substring(search.length());
            }
        }
        return null;
    }
    public int valueOfInt(String name, int def){
        String value = this.valueOf(name);
        if (null != value)
            return Integer.parseInt(name);
        else
            return def;
    }
    public long valueOfLong(String name, long def){
        String value = this.valueOf(name);
        if (null != value)
            return Long.parseLong(name);
        else
            return def;
    }
    public String[] valueOf(String name, String sep){
        String value = this.valueOf(name);
        if (null != value)
            return value.split(sep);
        else
            return null;
    }
    public void add(String line){
        this.list = Add(this.list,line);
    }
    public void add(String name, String value){
        if (null != name && null != value){
            String header = (name+Sep+value);
            this.list = Add(this.list,header);
        }
    }
    public String remove(String name){
        int idx = this.indexOf(name);
        if (-1 < idx){
            String[] list = this.list;
            String re = list[idx];
            int len = list.length;
            int trm = (len-1);
            String[] nlist = new String[trm];
            if (0 == idx){
                System.arraycopy(list,1,nlist,0,trm);
            }
            else if (trm == idx){
                System.arraycopy(list,0,nlist,0,trm);
            }
            else {
                System.arraycopy(list,0,nlist,0,idx);
                System.arraycopy(list,(idx+1),nlist,idx,(trm-idx));
            }
            this.list = nlist;
            return re;
        }
        else
            return null;
    }
    public void set(String name, String value){
        if (null != name && null != value){
            String header = (name+Sep+value);
            int idx = this.indexOf(name);
            if (-1 < idx)
                this.list[idx] = header;
            else 
                this.list = Add(this.list,header);
        }
    }
    public void setDate(String name, long time){
        this.set(name,Date.ToString(time));
    }
    public void setDate(){
        this.setDate("Date",System.currentTimeMillis());
    }
    public long getDate(String name){
        String value = this.valueOf(name);
        if (null != value)
            return new java.util.Date(value).getTime();
        else
            return 0L;
    }
    public String getHost(){
        return this.valueOf("Host");
    }
    public boolean hasHost(){
        return (-1 < this.indexOf("Host"));
    }
    public String getHostName(){
        String host = this.valueOf("Host").toLowerCase();
        int idx = host.indexOf(':');
        if (0 < idx)
            return host.substring(0,idx);
        else
            return host;
    }
    public String getConnection(){
        return this.valueOf("Connection");
    }
    public void setConnectionKeepAlive(){
        this.set("Connection","keep-alive");
    }
    public boolean isConnectionKeepAlive(){
        String value = this.getConnection();
        return (null != value && "keep-alive".equalsIgnoreCase(value));
    }
    public boolean isNotConnectionKeepAlive(){
        String value = this.getConnection();
        return (null == value || (!"keep-alive".equalsIgnoreCase(value)));
    }
    public void setConnectionClose(){
        this.set("Connection","close");
    }
    public boolean isConnectionClose(){
        String value = this.getConnection();
        return (null != value && "close".equalsIgnoreCase(value));
    }
    public boolean isNotConnectionClose(){
        String value = this.getConnection();
        return (null == value || (!"close".equalsIgnoreCase(value)));
    }
    public long getContentLength(){
        return this.valueOfLong("Content-Length",-1L);
    }
    public void setContentType(String value){
        if (null != value)
            this.set("Content-Type",value);
        else
            this.set("Content-Type","text/plain");
    }
    public void setContentTypeFor(java.io.File file){
        this.setContentType(Mimetype.For(file));
    }
    public void setContentTypeFor(java.net.URI uri){
        this.setContentType(Mimetype.For(uri));
    }
    public void setLastModifiedFor(java.io.File file){
        long last = file.lastModified();
        if (0L < last)
            this.setDate("Last-Modified",last);
    }
    public void setContentLengthFor(java.io.File file){
        long len = file.length();
        this.set("Content-Length",String.valueOf(len));
    }
    public void read(Input in)
        throws IOException
    {
        String line;
        while (null != (line = in.readLine())){
            if (null != line && 0 < line.length()){
                this.add(line);
            }
        }
    }
    public void write(Output out)
        throws IOException
    {
        String[] headers = this.list;
        if (null != headers){
            for (int cc = 0, count = headers.length; cc < count; cc++){
                String header = headers[cc];
                if (null != header && 0 < header.length())
                    out.println(header);
            }
        }
        out.println();
    }
    public void write(PrintStream out){
        String[] headers = this.list;
        if (null != headers){
            for (int cc = 0, count = headers.length; cc < count; cc++){
                String header = headers[cc];
                if (null != header && 0 < header.length())
                    out.println(header);
            }
        }
        out.println();
    }

}
